package com.xncoding.pos.config.norepeat;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.connection.ReturnType;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 文件名：JedisDistributedLock.java
 *
 * @create 2019-11-25 14:54
 * <p>
 * <p>
 */
@Component
public class JedisLock {
    private final Logger logger = LoggerFactory.getLogger(JedisLock.class);

//    private DefaultRedisScript<Boolean> lockScript;
    @Resource
    private RedisTemplate<Object, Object> redisTemplate;

    private static final String UNLOCK_LUA;

    static {
        StringBuilder sb = new StringBuilder();
        sb.append("if redis.call(\"get\",KEYS[1]) == ARGV[1] ");
        sb.append("then ");
        sb.append("    return redis.call(\"del\",KEYS[1]) ");
        sb.append("else ");
        sb.append("    return 0 ");
        sb.append("end ");
        UNLOCK_LUA = sb.toString();
    }


    public boolean setLock(String key,String val, long expire) {
        logger.info("----lockKey------>"+key+"--->"+val+"---->"+expire);
        try {
            return redisTemplate.execute(new RedisCallback<Boolean>() {
                @Override
                public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                    return connection.set(key.getBytes(), val.getBytes(), Expiration.seconds(expire) , RedisStringCommands.SetOption.ifAbsent());
                }
            });
        } catch (Exception e) {
            logger.error("set redis occured an exception", e);
        }
        return false;
    }

    /**
     * 释放锁操作
     * @param key
     * @param value
     * @return
     */
    public boolean releaseLock(final String key, final String value) {
        RedisCallback<Boolean> callback = (connection) -> {
                return connection.eval(UNLOCK_LUA.getBytes(), ReturnType.BOOLEAN ,1, key.getBytes(), value.getBytes());
            };
        return redisTemplate.execute(callback);
        /*lockScript = new DefaultRedisScript<Boolean>();
        lockScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("unlock.lua")));
        lockScript.setResultType(Boolean.class);
        // 封装参数
        List<Object> keyList = new ArrayList<Object>();
        keyList.add(key);
        keyList.add(value);
        return (Boolean) redisTemplate.execute(lockScript, keyList);*/
    }
}
